﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using GeoSketch2.Core;
using System.Xml;

namespace GeoSketch2.Archaeo
{
    // <summary>
    /// A subdivision of the main excavation site
    // </summary>
    public class _ExcavationSquare : BaseExcavationArea
    {
        #region XML
#pragma warning disable 1591
        public const string XML_SquareUnits = "SquareUnits";
#pragma warning restore 1591
        #endregion

        #region Fields
        // <summary>
        /// The list of the excavation unit contained in the square
        // </summary>
        public List<ExcavationUnit> ExcavationUnits;

        // <summary>
        /// The main excavation site
        // </summary>
        public ExcavationSite ParentExcavationSite;
        #endregion

        #region Constructor
        /// <summary>
        /// A subdivision of the main excavation site
        /// </summary>
        /// <param name="Site">The excavation site containing the square</param>
        public ExcavationSquare(ExcavationSite Site)
            : this("Square"+Site.ExcavationSquares.Count,"",DateTime.Now,Site.Bounds.DeepClone(),new List<Layer>(),Site)
        { 
        }

        /// <summary>
        /// A subdivision of the main excavation site
        /// </summary>
        /// <param name="Name">The name of the square</param>
        /// <param name="ArchaeologistName">The name of the archaeologist</param>
        /// <param name="CreationTime">The time of creation</param>
        /// <param name="Bounds">The bounds of the area in object coordinates, Y-axis upside</param>
        /// <param name="AvailableLayers">The available layers from this area</param>
        /// <param name="ParentSite">The excavation site containing the square</param>
        public ExcavationSquare(string Name, string ArchaeologistName, DateTime CreationTime, Point2D64D[] Bounds, List<Layer> AvailableLayers,ExcavationSite ParentSite)
            : base(Name,ArchaeologistName,CreationTime,Bounds,AvailableLayers)
        {
            this.ParentExcavationSite = ParentSite;
            this.ExcavationUnits = new List<ExcavationUnit>();
            this.ParentExcavationSite.ExcavationSquares.Add(this);

            if (AvailableLayers.Count == 0)
            {
                Layer DefaultLayer = new Layer(Name + "DefaultLayer", Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.DefaultLayerColor, Project.DefaultLineType, true);
                AvailableLayers.Add(DefaultLayer);
                Project.ProjectLayers.Add(DefaultLayer);
            }

            this.AreaTreeDepth = 1;
        }

        /// <summary>
        /// A subdivision of the main excavation site
        /// </summary>
        /// <param name="Xr">The xml reader to read from</param>
        /// <param name="Site">The parent site of the square</param>
        public ExcavationSquare(XmlReader Xr, ExcavationSite Site)
            : base(Xr, Site)
        {
            this.ParentExcavationSite = Site;
            this.ExcavationUnits = new List<ExcavationUnit>();
            this.ParentExcavationSite.ExcavationSquares.Add(this);

            if (AvailableLayers.Count == 0)
            {
                Layer DefaultLayer = new Layer(Name + "DefaultLayer", Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.DefaultLayerColor, Project.DefaultLineType, true);
                this.AvailableLayers.Add(DefaultLayer);
                this.Project.ProjectLayers.Add(DefaultLayer);
            }

            Xr.ReadToFollowing(XML_SpecificInfos);

            Xr.ReadToFollowing(XML_SquareUnits);
            if (!Xr.IsEmptyElement)
            {
                Xr.ReadToFollowing(typeof(ExcavationUnit).FullName);
                while (!(Xr.NodeType == XmlNodeType.EndElement && Xr.Name == XML_SquareUnits))
                {
                    new ExcavationUnit(Xr, this);
                    Xr.ReadEndElement();
                }
                Xr.ReadEndElement();
            }
            else
            {
                Xr.Read();
            }

            Xr.ReadEndElement();
        }
        #endregion

        #region Methods
        /// <summary>
        /// The method used if the area has something to draw, which is not a geo object
        /// </summary>
        /// <param name="Viewport">The viewport the area will draw to</param>
        public override void Draw(Viewport Viewport)
        {
            foreach (ExcavationUnit u in ExcavationUnits)
            {
                PointF[] bounds_screen_coordinates = Viewport.Object2ImageTransformation.TransformF(u.Bounds);
                GraphicsPath path = new GraphicsPath(bounds_screen_coordinates, Tools.GetPathPointsType(bounds_screen_coordinates.Length));
                Viewport.Graphic.DrawPath(Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.ExcavationUnitsDisplayPen, path);

                Point2D64D BoundsCentroid = u.Bounds.GetCentroid();
                BoundsCentroid = Viewport.Object2ImageTransformation.Transform(BoundsCentroid);
                SizeF StringSize = Viewport.Graphic.MeasureString(u.Name, Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.NameFontdisplay);
                BoundsCentroid.X -= StringSize.Width / 2;
                BoundsCentroid.Y -= StringSize.Height / 2;
                Viewport.Graphic.DrawString(u.Name, Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.NameFontdisplay, Vars.Setup.StandardObjects.ExcavationAreas.ExcavationSquare.ExcavationUnitsDisplayPen.Brush, BoundsCentroid);
            }
        }

        /// <summary>
        /// Writes the object to a file
        /// </summary>
        /// <param name="Xw">The XmlWriter to write to</param>
        public void ToFile(XmlWriter Xw)
        {
            Xw.WriteStartElement(this.GetType().FullName);

            #region Square Base Information
            Xw.WriteStartElement(XML_BaseInfos);

            #region Square Name
            Xw.WriteStartElement(XML_Name);
            Xw.WriteString(this.Name);
            Xw.WriteEndElement();
            #endregion

            #region Square Creation Date
            Xw.WriteStartElement(XML_CreationDate);
            Xw.WriteString(this.CreationTime.ToBinary().ToString(Core.Vars.Setup.GeoSketch.NumberFormat));
            Xw.WriteEndElement();
            #endregion

            #region Square Archaeologist Name
            Xw.WriteStartElement(XML_Archaeologist);
            Xw.WriteString(this.ArchaeologistName);
            Xw.WriteEndElement();
            #endregion

            #region Square Bounds
            Xw.WriteStartElement(XML_Bounds);
            foreach (Point2D64D p in this.Bounds)
            {
                p.ToFile(Xw);
            }
            Xw.WriteEndElement();
            #endregion

            #region Square Available Layers
            Xw.WriteStartElement(XML_AvailableLayers);
            foreach (Layer l in this.AvailableLayers)
            {
                Xw.WriteStartElement(Layer.XML_Name);
                Xw.WriteString(l.Name);
                Xw.WriteEndElement();
            }
            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
            #endregion

            #region Square Specific Information
            Xw.WriteStartElement(XML_SpecificInfos);

            #region Units
            Xw.WriteStartElement(XML_SquareUnits);
            foreach (ExcavationUnit u in this.ExcavationUnits)
            {
                u.ToFile(Xw);
            }
            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement();
            #endregion

            Xw.WriteEndElement(); 
        }
        #endregion

        #region Properties
        // <summary>
        /// Gets the digging height of the square
        // </summary>
        public override DiggingHeight DiggingHeight
        {
            get
            {
                DiggingHeight dst = new DiggingHeight();

                foreach (ExcavationUnit u in ExcavationUnits)
                {
                    dst.MaxHeight = Math.Max(dst.MaxHeight, u.DiggingHeight.MaxHeight);
                    dst.MinHeight = Math.Max(dst.MinHeight, u.DiggingHeight.MinHeight);
                }

                return dst;
            }
            set
            {
                throw new Exception("Forbidden");
            }
        }

        /// <summary>
        /// Gets the treeview node of the area
        /// </summary>
        public override TreeNode TreeViewNode
        {
            get
            {
                TreeNode node = new TreeNode(Name, Vars.Setup.Forms.DrawingForm.TreeViewSquareImageIndex, Vars.Setup.Forms.DrawingForm.TreeViewSquareImageIndex);
                node.Tag = this;

                foreach (ExcavationUnit unit in ExcavationUnits)
                {
                    node.Nodes.Add(unit.TreeViewNode);
                }

                return node;
            }
        }

        /// <summary>
        /// Gets the path of the area, the path from the main excavation site
        /// </summary>
        public override string Path
        {
            get
            {
                return ParentExcavationSite.Path+" - "+Name;
            }
        }
        #endregion
    }
}
